/*
* ============================================================================
*  Name        : example_006.cpp
*  Part of     : Finite state machine examples
*  Description : Dispatching state machine in existing event handling systems
*              : like Qt
*  Version     : %version: %
*  
*
* ============================================================================
*/
#include "example_006.h"
#include "example_006.hxx" // State machine source code is here

/**
 * @file example_006.cpp
 *
 * @details
 * \b 'user_dispatched' mode. Dispatching state machine in existing event handling systems like Qt.
 *
 * @ingroup StateMachineExamples
 */
using namespace sea_examples;

const int RightArrowKeyCode = 77;
const int LeftArrowKeyCode = 75;

// ----------------------------------------------------------------------------
// Create and dispatch the state machine outside of the framework
// ----------------------------------------------------------------------------
void sea_examples::launch_example_006( )
{
    SEA_TRACE_ENTRY( );

    {
        sea::ref< Embedded > sm;
        sm << NEW Embedded( 10 );

        if ( sm->create( 0, Embedded_src ) != eOk ){ /* See Error codes */ }
        if ( sm->start( StateMachine::RunDispatched ) != eOk ){ /* See Error codes */ }

        // Get some random events
        srand( ( unsigned )time( NULL ) ); 

        // Stick the sm->dispatch( ) in your event loop
        while( sm->dispatch( ) == eOk )
        {
            int hint = rand( );

            if( hint % 5 == 0 )
            {
                sm->push_event( sm->Ev_Ext_UserKey( ), RightArrowKeyCode );
            }
            if( hint % 7 == 0 )
            {
                sm->push_event( sm->Ev_Ext_UserKey( ), LeftArrowKeyCode );
            }
        }
        // At this point state machines associated with the dispatcher are finished
    }
    Engine::terminate( );
}

// ----------------------------------------------------------------------------
// Same as above but with multiple instances. When more then one 
// state machine launched, use Manager assigned to the state machine 
// for dispatching
// ----------------------------------------------------------------------------
void sea_examples::launch_example_0061( )
{
    SEA_TRACE_ENTRY( );

    {
        sea::ref< Embedded > sm1;
        sm1 << NEW Embedded( 10 );

        if ( sm1->create( 0, Embedded_src ) != eOk ){ /* See Error codes */ }
        if ( sm1->start( StateMachine::RunDispatched ) != eOk ){ /* See Error codes */ }

        sea::ref< Embedded > sm2;
        sm2 << NEW Embedded( 20 );

        if ( sm2->create( 0, Embedded_src ) != eOk ){ /* See Error codes */ }

        // State machine gets assigned to the manager/thread
        Manager* the_dispatcher = sm1->dispatcher( );

        // Other state machines can join to the existing one
        // inheariting execution mode 
        the_dispatcher->join( sm2.get( ) );

        // Get some random events
        srand( ( unsigned )time( NULL ) ); 

        // Stick the manager->dispatch( ) in your event loop
        while( the_dispatcher->dispatch( ) == eOk )
        {
            int hint = rand( );

            if( hint % 5 == 0 )
            {
                sm1->push_event( sm1->Ev_Ext_UserKey( ), RightArrowKeyCode );
            }
            else
            if( hint % 7 == 0 )
            {
                sm1->push_event( sm1->Ev_Ext_UserKey( ), LeftArrowKeyCode );
            }
            else
            if( hint % 9 == 0 )
            {
                sm2->push_event( sm2->Ev_Ext_UserKey( ), RightArrowKeyCode );
            }
            else
            if( hint % 11 == 0 )
            {
                sm2->push_event( sm2->Ev_Ext_UserKey( ), LeftArrowKeyCode );
            }
            else
            {
                // Simulate wrong key
                sm1->push_event( sm1->Ev_Ext_UserKey( ), -1 );
                sm2->push_event( sm2->Ev_Ext_UserKey( ), -1 );
            }
        }

        // At this point state machines associated with the dispatcher are finished
    }

    Engine::terminate( );
}

// ----------------------------------------------------------------------------

ACT_IMPL( Embedded, process_key_press )
{
    switch( ( int )ACT_EVENT_PARAM( ) )
    {
    case RightArrowKeyCode:
        push_event( Ev_Int_MoveRight( ) );
        break;
    case LeftArrowKeyCode:
        push_event( Ev_Int_MoveLeft( ) );
        break;
    default:
        push_event( Ev_Int_WrongKey( ) );
        break;
    }
}

// ----------------------------------------------------------------------------

ACT_IMPL( Embedded, on_right_move )
{
    SEA_UNUSED_PARAM( );
    SEA_TRACE( "... moving to the right..." );
}

// ----------------------------------------------------------------------------

ACT_IMPL( Embedded, on_left_move )
{
    SEA_UNUSED_PARAM( );
    SEA_TRACE( "... moving to the left..." );
}

// ----------------------------------------------------------------------------

ACT_IMPL( Embedded, wrong_move )
{
    SEA_UNUSED_PARAM( );
    ++m_wrong_moves_counter;
    SEA_TRACE( "... Wrong moves: %d limit %d", m_wrong_moves_counter, m_limit );

    if( m_wrong_moves_counter == m_limit )
    {
        push_event( terminate_event_id( ) );
    }
}

// ----------------------------------------------------------------------------

ACT_IMPL( Embedded, unknown_key )
{
    SEA_UNUSED_PARAM( );
    SEA_TRACE( "... dont know such a key..." );
}

// ----------------------------------------------------------------------------

ACT_IMPL( Embedded, good_bye )
{
    SEA_UNUSED_PARAM( );
    SEA_TRACE( "... GOOD BYE..." );
}

// ----------------------------------------------------------------------------

